package com.zecan.blog.service.impl;

import com.google.code.kaptcha.Producer;
import com.zecan.blog.common.status.BlogCommonStatus;
import com.zecan.blog.common.status.UserStatus;
import com.zecan.blog.controller.exception.BlogException;
import com.zecan.blog.controller.exception.UserException;
import com.zecan.blog.dao.UserMapper;
import com.zecan.blog.dao.converter.BlogUserConverter;
import com.zecan.blog.dto.user.RegistryUserDto;
import com.zecan.blog.dto.user.UpdateUserInfoDto;
import com.zecan.blog.entity.BlogUser;
import com.zecan.blog.entity.UserCenterBlogInfo;
import com.zecan.blog.rabbitmq.BlogMqProducer;
import com.zecan.blog.rabbitmq.event.SendEmailEvent;
import com.zecan.blog.service.BlogUserService;
import com.zecan.blog.utils.*;
import com.zecan.blog.vo.user.UserCenterBlogInfoVo;
import com.zecan.blog.vo.user.bgUserInfoVo;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.*;

/**
 * @ClassName UserServiceImpl
 * @Description
 * @date 2022/10/29 18:11
 * @Version 1.0
 * User业务层实现类
 */
@Service
public class BlogUserServiceImpl implements BlogUserService {


    @Resource
    private UserMapper userMapper;
    @Resource
    private HttpServletResponse response;

    @Resource
    private Producer producer; // 获取验证码接口

    @Resource
    private RedisUtils redisUtils;

    @Resource
    private MailSendUtil mailSendUtil;

    @Resource
    private AliOssUtils aliOssUtils;

    @Resource
    private BlogMqProducer blogMqProducer;


    @Override
    public BlogUser selectUserByUsername(String Username) {
        return userMapper.findUserByUsername(Username);
    }

    @Override
    public void getCaptchaImg(String captchaKey) {
        // 获取验证码
        String code = producer.createText();

        // 根据验证码获取图片
        BufferedImage image = producer.createImage(code);
        ServletOutputStream outputStream = null;
        try {
            // 图片写入
            outputStream = response.getOutputStream();
            ImageIO.write(image, "jpeg", outputStream);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //redis insert  将图片信息保存到redis中 进行验证的时候获取
        redisUtils.hashSet(BlogConstant.CAPTCHA_KEY, captchaKey, code, 120);
    }

    /**
     * 用户信息校验
     *
     * @param dto 用户注册信息
     */
    @Override
    public void checkMsg(RegistryUserDto dto) {
        // 注册发生未知异常
        if (dto == null) {
            throw new UserException(UserStatus.USER_REG_ERR);
        }
        String username = dto.getUsername();
        String password = dto.getPassword();
        ;
        String captcha = dto.getEmailCaptcha(); // 用户输入的邮箱验证码
        String captchaKey = dto.getCaptchaKey(); // 获取hashKey

        BlogUser userByUsername = userMapper.findUserByUsername(username);
        // 当前用户名已注册
        if (userByUsername != null) {
            throw new UserException(UserStatus.USER_NAME_ALREADY_REG);
        }

        // 用户名过短
        if (username.length() < USERNAME_MIN_LENGTH) {
            throw new UserException(UserStatus.USER_NAME_TOO_SHORT);
        }
        // 用户名过长
        if (username.length() > USERNAME_MAX_LENGTH) {
            throw new UserException(UserStatus.USER_NAME_TOO_LONG);
        }

        // 密码过短
        if (password.length() < PASSWORD_MIN_LENGTH) {
            throw new UserException(UserStatus.USER_PASS_SHORT);
        }
        //查询redis 中是否存在当前验证码
        checkEmailCode(captcha,captchaKey);

    }

    @Override
    public UserCenterBlogInfoVo getUserBlogInfo(Integer userId) {
        // 查询当前id是否存在
        BlogUser userByUserId = this.userMapper.findUserByUserId(userId);
        if (userByUserId == null) {
            throw new UserException(UserStatus.USER_NOT_FOUND);
        } else {
            // 获取当前id的博客信息集
            List<UserCenterBlogInfo> userBlogInfoByUserId = this.userMapper.findUserBlogInfoByUserId(Collections.singletonList(userId));
            // 获取第一个主信息集合==> 为当前请求的用户
            UserCenterBlogInfo info =  userBlogInfoByUserId.get(0);
            //信息封装
            UserCenterBlogInfoVo userCenterBlogInfoVo = UserCenterBlogInfoVo.getUserCenterBlogInfoVo(info);
            // 如果有关注子信息 继续获取
            if (info.getFollowIds() != null) {
                List<UserCenterBlogInfoVo> followList = new ArrayList<>();

                // 获取id list
                List<Integer> followIds = getFollowIds(info.getFollowIds());
                // 关注信息获取并筛入到vo中
                List<UserCenterBlogInfo> followUserInfos = this.userMapper.findUserBlogInfoByUserId(followIds);
                followUserInfos.forEach((userCenterBlogInfo) -> {
                    followList.add(UserCenterBlogInfoVo.getUserCenterBlogInfoVo(userCenterBlogInfo));
                });
                userCenterBlogInfoVo.setFollowList(followList);
            }
            // 如果有粉丝信息 获取粉丝信息集合
            if(info.getFollowerIds() != null) {
                List<UserCenterBlogInfoVo> followerList = new ArrayList<>();

                // 获取id list
                List<Integer> followIds = getFollowIds(info.getFollowerIds());

                // 粉丝信息获取并筛入到vo中
                List<UserCenterBlogInfo> followUserInfos = this.userMapper.findUserBlogInfoByUserId(followIds);
                followUserInfos.forEach((userCenterBlogInfo) -> {
                    followerList.add(UserCenterBlogInfoVo.getUserCenterBlogInfoVo(userCenterBlogInfo));
                });
                userCenterBlogInfoVo.setFollowerList(followerList);
            }

            return userCenterBlogInfoVo;
        }
    }

    @Override
    public List<bgUserInfoVo> getBgUserInfoList(Integer offset, Integer limit) {
        List<bgUserInfoVo> list = new ArrayList<>();

        List<BlogUser> userList = userMapper.findUserList(offset, limit);
        Integer userCount = userMapper.findUserCount();
        userList.forEach(item -> {
            list.add(bgUserInfoVo.bgUserInfoVo(item));
        });
        list.get(0).setUserCount(userCount);
        return list;
    }

    @Override
    public void updateBgUserInfo(UpdateUserInfoDto updateUserInfoDto) {
        BlogUser blogUser = null;
        if(updateUserInfoDto != null) {
             blogUser = BlogUserConverter.INSTANCE.bgUserUpdateConverterEntity(updateUserInfoDto);
        }else {
            throw new UserException(UserStatus.USER_UPDATE_INFO_ERR);
        }
        // 查询当前用户是否存在
        Long userId = blogUser.getUserId();
        if(userMapper.findUserIsExits(userId).equals(0)){
            throw new UserException(UserStatus.USER_NOT_FOUND);
        }
        // 修改信息
        blogUser.setPassword( new BCryptPasswordEncoder().encode(blogUser.getPassword()));
        userMapper.updateBgUserInfo(blogUser);
    }

    @Override
    public void delUser(Integer userId) {
        userMapper.updateUserStatus(userId);
    }

    @Override
    public void resetUserPwd(Integer userId) {
        String pwd = new BCryptPasswordEncoder().encode("12345678");
        userMapper.updateUserPwd(userId,pwd);
    }

    @Override
    public void sendEmailMsg(String email, String emailKey, Boolean isRegistry) {
        // 如果当前不是正确的邮箱格式
        if (!StringUtils.isEmail(email)) {
            throw new UserException(UserStatus.USER_EMAIL_FORMAT_ERR);
        }
        // 获取随机5位验证码
        String emailCode = StringUtils.random();

        // 判定当前是否是注册
        if (isRegistry) {
            // 查询当前邮箱是否已经注册过
            if (!selectUserEmailExits(email)) {
                throw new UserException(UserStatus.USER_EMAIL_ALREADY_EXISTS);
            }
            // 发送邮箱 交给rabbitmq
            blogMqProducer.sendEmailMessage(BlogConstant.RABBITMQ_EXCHANGE,BlogConstant.RABBITMQ_SEND_EMAIL_ROUTING_KEY,
                    SendEmailEvent.builder().subject("zBlog注册验证码!请注意查收").toUser(email).isRegistry(true).content(emailCode).build()
            );
        } else {
            blogMqProducer.sendEmailMessage(BlogConstant.RABBITMQ_EXCHANGE,BlogConstant.RABBITMQ_SEND_EMAIL_ROUTING_KEY,
                    SendEmailEvent.builder().subject("zBlog修改个人中心验证码!请注意查收").toUser(email).isRegistry(false).content(emailCode).build()
            );
        }

        // 发送成功后保存到redis中 如果没有发送成功会直接报错
        redisUtils.hashSet(BlogConstant.EMAIL_CODE, emailKey, emailCode, 120);

    }

    /**
     * //TODO : 可以在前端进行传递表单的时候再次加密
     * yoghurt注册
     *
     * @param entity 用户实体类
     */
    @Override
    public void registryBlogUser(BlogUser entity) {
        // 数据初始化
        entity.setUserRegisterTime(StringUtils.dateFormat(new Date()));
        entity.setUserRole(entity.getUserRole() != null ?entity.getUserRole() : 0 );
        // 密码加密
        entity.setPassword(new BCryptPasswordEncoder().encode(entity.getPassword()));
        entity.setUserGender(1);
        entity.setUserAvatarUrl("https://unsplash.it/100/100?image=307");
        entity.setUserNickname(entity.getUsername());
        entity.setUserStatus(0);
        // 返回影响的行数
        Integer col = userMapper.insertUser(entity);
        if (col != 1) {
            throw new UserException(UserStatus.USER_REG_ERR);
        }
    }

    // 如果当前邮箱没有注册过则是null
    @Override
    public Boolean selectUserEmailExits(String email) {
        return Objects.isNull(userMapper.findUserByEmail(email));
    }

    @Override
    public String uploadUserAvatar(MultipartFile multipartFile) {
        try {
            // 头像上传
          return  aliOssUtils.upload(multipartFile.getInputStream(),"article/userAvatarImg", multipartFile.getOriginalFilename());
        } catch (IOException e) {
            throw new BlogException(BlogCommonStatus.UPLOAD_IMAGE_FAIL);
        }
    }

    @Override
    public void updateUserInfo(BlogUser blogUser) {
        String emailCaptcha  = blogUser.getEmailCaptcha();
        String captchaKey = blogUser.getCaptchaKey();
        String password = blogUser.getPassword();
        String email = blogUser.getUserEmail();
        // 在redis中获取数据 验证验证码是否正确
        checkEmailCode(emailCaptcha, captchaKey);

        // 更新的时候根据邮箱判断当前邮箱是否有修改且是否有人使用
        String userEmailById = userMapper.findUserEmailById(blogUser.getUserId());
        if(!userEmailById.equals(email)) {
            // 判断当前邮箱格式
            if (!StringUtils.isEmail(email)) {
                throw new UserException(UserStatus.USER_EMAIL_FORMAT_ERR);
            }
            // 判断当前邮箱是否有人使用
            if(!selectUserEmailExits(email)) {
                throw new UserException(UserStatus.USER_EMAIL_ALREADY_EXISTS);
            }
        }
        if(password.length() != 0) {
            blogUser.setPassword(new BCryptPasswordEncoder().encode(password));
        }

        // 更新数据
        Integer col = userMapper.updateUserInfo(blogUser);
        if(col == 0) {
            throw  new UserException(UserStatus.USER_UPDATE_INFO_ERR);
        }
    }


    // 检查验证码
    public void checkEmailCode(String emailCaptcha,String captchaKey) {
        String redisCaptcha = (String) redisUtils.hashGet(BlogConstant.EMAIL_CODE, captchaKey);
        // 验证码过期
        if(redisCaptcha == null) {
            throw new UserException(UserStatus.USER_CAPTCHA_EXPIRE);
        }
        //验证码输入错误
        if(!redisCaptcha.equals(emailCaptcha)) {
            throw new UserException(UserStatus.USER_CAPTCHA_ERR);
        }
        //删除redis中的数据
        redisUtils.delHash(BlogConstant.EMAIL_CODE,captchaKey);
    }


    // 传递 ids 字符串 返回 list集合
    public List<Integer> getFollowIds(String ids) {
        String[] split = null;
        List<Integer> followIds = null;
        split = ids.split(",");

        followIds = new ArrayList<>();

        for (String s : split) {
            followIds.add(Integer.valueOf(s));
        }

        return followIds;
    }
}
